import shutil
import subprocess
import time
from datetime import datetime
import os
from flask import Flask, request, jsonify
from werkzeug.utils import safe_join
from flask_mysqldb import MySQL
from flask_cors import CORS
import numpy as np
import geatpy as ea

app = Flask(__name__)
CORS(app, resources={r"/*": {"origins": "*"}})  # 设置跨域

# 配置MySQL连接
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'vrpsdptw'
app.config['MYSQL_PASSWORD'] = '123456'
app.config['MYSQL_DB'] = 'vrpsdptw'

mysql = MySQL(app)


@app.route('/test', methods=['POST'])
def add_test():
    json_data = request.get_json()
    name = json_data.get('name')
    age = json_data.get('age')
    cur = mysql.connection.cursor()
    cur.execute('INSERT INTO test (name,age) '
                'VALUES (%s, %s)', (name, age))
    mysql.connection.commit()
    cur.close()
    data = json_data
    return "hello world"


@app.route('/get-algor')
def get_algor():
    CS = mysql.connection.cursor()
    CS.execute('''SELECT * FROM algor_table''')
    mysql.connection.commit()
    data = CS.fetchall()
    # 将日期字段转换为指定格式
    formatted_data = []
    for row in data:
        formatted_row = list(row)
        # 假设日期字段在第三列，这里做相应调整
        formatted_row[3] = row[3].strftime('%Y-%m-%d %H:%M:%S')
        formatted_data.append(formatted_row)
    # print(Executed_DATA)
    return jsonify(formatted_data)


@app.route('/modify-algor', methods=['POST'])
def modify_algor():
    CS = mysql.connection.cursor()
    # 解析请求体中的数据
    data = request.json

    sql = f"UPDATE algor_table SET name = '{data['name']}', " + \
          f"title = '{data['title']}', create_time = '{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}', " + \
          f"url = '{data['url']}',  tags = '{data['tag']}', description = '{data['description']}' " + \
          f"WHERE id = {data['id']}"
    print(sql)

    CS.execute(sql)
    mysql.connection.commit()
    affected_rows = CS.rowcount
    print("受影响的行数:", affected_rows)

    return jsonify('Data inserted successfully')


@app.route('/get-file', methods=['GET'])
def get_file():
    # 获取请求参数中的目录和文件名
    directory = '../SDPPTW_data/'
    filename = request.args.get('filename')
    c_num = request.args.get('c_num')
    file_type = request.args.get('file_type')

    print(f"file_type:{file_type}")

    # 安全地构建文件路径
    try:
        filepath = safe_join(directory, filename)
    except ValueError:
        return jsonify({"error": "Invalid directory or filename."}), 400

    # 检查文件是否存在
    if not os.path.exists(filepath):
        return jsonify({"error": "File not found."}), 404

    data = []
    if file_type == '3':
        with open(filepath, 'r') as file:
            # 跳过文件的前四行
            for _ in range(4):
                file.readline()
            # 读取最大容量值
            specLine = file.readline().strip().split()
            vehicle_num = int(specLine[0])
            max_capacity = float(specLine[1])
            # 再次跳过四行
            for _ in range(4):
                file.readline()

            for i in range(int(c_num) + 1):
                line = file.readline()
                row = [float(val) for val in line.split()]
                # 将每行分割成浮点数列表
                data.append(row)

        result = {
            "vehicle_num": vehicle_num,
            "max_capacity": max_capacity,
            "data": data
        }

        return jsonify(
            result
        )
    else:
        with open(filepath, 'r') as file:
            for line in file:
                # 将每行分割成浮点数列表
                row = [float(val) for val in line.split()]
                data.append(row)
        # 返回文件内容
        return jsonify(data)


@app.route('/upload', methods=['POST'])
def upload_file():
    print(request.form)

    folder_name = request.form['name']
    url = request.form['url']
    tag = request.form['tag']
    title = request.form['title']
    description = request.form['description']
    index = request.form['index']
    source = '../' + folder_name + '/' + index
    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    CS = mysql.connection.cursor()
    sql = f"Insert into algor_table (name, title, create_time,url, source, tags,description)" + \
          f"values('{folder_name}','{title}','{current_time}','{url}','{source}','{tag}','{description}')"
    # print(sql)
    CS.execute(sql)
    mysql.connection.commit()

    folder_path = '../' + folder_name
    os.makedirs(folder_path, exist_ok=True)

    print(request.files.getlist('files'))
    # if 'file' not in request.files:
    #     return '没有文件部分', 400

    uploaded_files = request.files.getlist('files')
    # print(uploaded_files)
    for file in uploaded_files:
        if file:
            filename = file.filename
            # print(filename)
            save_path = os.path.join(folder_path, filename)
            file.save(save_path)
    return '文件上传成功', 200


@app.route('/delete-algor', methods=['POST'])
def delete_record():
    data = request.json
    record_id = data['id']
    CS = mysql.connection.cursor()
    CS.execute(f"select name FROM algor_table WHERE id = {record_id}")
    mysql.connection.commit()
    data = CS.fetchall()
    algor_folder = '../' + data[0][0]
    # shutil.rmtree(algor_folder)
    # print(algor_folder)
    try:
        # 执行删除操作
        CS.execute(f"DELETE FROM algor_table WHERE id = {record_id}")
        mysql.connection.commit()
        return jsonify({'message': '删除成功'}), 200
    except Exception as e:
        mysql.connection.rollback()
        return jsonify({'message': '删除失败', 'error': str(e)}), 500


@app.route('/get-process', methods=['GET'])
def get_process():
    CS = mysql.connection.cursor()
    CS.execute('''SELECT * FROM process_table''')
    mysql.connection.commit()
    data = CS.fetchall()
    # 将日期字段转换为指定格式
    formatted_data = []
    for row in data:
        formatted_row = list(row)

        # 获取算法名
        id = formatted_row[1]
        CS.execute(f"SELECT name from algor_table WHERE {id}=algor_table.id")
        mysql.connection.commit()
        data = CS.fetchall()
        formatted_row.append(data[0])

        # 假设日期字段在第八列，这里做相应调整
        formatted_row[8] = row[8].strftime('%Y-%m-%d %H:%M:%S')
        formatted_data.append(formatted_row)

    # print(Executed_DATA)
    return jsonify(formatted_data)


@app.route('/delete-process', methods=['POST'])
def delete_process():
    data = request.json
    process_id = data['id']
    CS = mysql.connection.cursor()

    sql = f"select result_name FROM process_table WHERE id = {process_id}"
    CS.execute(sql)
    mysql.connection.commit()
    data = CS.fetchall()
    folder_path = '../Result/' + data[0][0]
    shutil.rmtree(folder_path)
    try:
        # 执行删除操作
        CS.execute(f"DELETE FROM process_table WHERE id = {process_id}")
        mysql.connection.commit()
        return jsonify({'message': '删除成功'}), 200
    except Exception as e:
        mysql.connection.rollback()
        return jsonify({'message': '删除失败', 'error': str(e)}), 500


@app.route('/get-result', methods=['GET'])
def get_result():
    # 获取请求参数中的目录和文件名
    directory = '../Result/'
    process_id = request.args.get('id')
    active_key = int(request.args.get('key'))

    print(process_id)
    print(active_key)

    if active_key == 0:
        txt_filename = 'final.txt'
    else:
        txt_filename = f'result{active_key}.txt'

    sql = f"select result_name from process_table where id={process_id}"
    CS = mysql.connection.cursor()
    CS.execute(sql)
    mysql.connection.commit()
    data = CS.fetchall()
    folder_name = data[0][0]
    folder_path = directory + folder_name
    print(folder_path)
    # 读取.txt文件内容
    txt_content = []
    with open(os.path.join(folder_path, txt_filename), 'r') as file:
        for line in file:
            # 将每行分割成浮点数列表
            row = [float(val) for val in line.split()]
            txt_content.append(row)

    length = len(txt_content)
    # 读取对应文件夹内容
    route_folder_name = txt_filename.replace('.txt', '') + "_route"
    folder_path = folder_path + '/' + route_folder_name
    folder_content = []
    # 注意这里要改成length
    for i in range(length):
        index = i + 1
        route_file_name = folder_path + '/' + f"route{index}.txt"
        file_data = []
        with open(route_file_name, 'r') as file:
            for line in file:
                # 将每行分割成浮点数列表
                row = [float(val) for val in line.split()]
                file_data.append(row)
        folder_content.append(file_data)

    response = {
        'txt_content': txt_content,
        'folder_content': folder_content
    }

    return jsonify(response)


@app.route('/add-process', methods=['POST'])
def add_process():
    print(request.form)

    algor_id = request.form['algor_name']
    c_num = request.form['c_num']
    c_type = request.form['c_type']
    i_time = request.form['i_time']
    s_time = request.form['s_time']
    w_type = request.form['w_type']

    data_name = 'Data_' + c_num + '_' + c_type + '_' + w_type

    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    time_format = "%Y-%m-%d %H:%M:%S"
    dt_obj = datetime.strptime(current_time, time_format)
    # 获取时间戳
    timestamp = dt_obj.timestamp()

    CS = mysql.connection.cursor()
    sql = f"select source,name from algor_table where id={algor_id}"
    CS.execute(sql)
    mysql.connection.commit()
    data = CS.fetchall()
    algor_source = data[0][0]
    algor_name = data[0][1]

    result_name = algor_name + str(timestamp)

    sql = f"Insert into process_table (algor_id, data_name, c_num,c_type, w_type, stop_time,iter_times,run_time,status,result_name)" + \
          f"values({algor_id},'{data_name}',{c_num},{c_type},{w_type},{s_time},{i_time},'{current_time}',0,'{result_name}')"

    CS.execute(sql)
    mysql.connection.commit()

    sql = f"select id from process_table where result_name='{result_name}'"
    CS.execute(sql)
    mysql.connection.commit()
    data = CS.fetchall()
    process_id = data[0][0]

    # 运行对应算法
    data_path = "../SDPPTW_data/"
    distance = data_path + "test" + c_num + "-0-0-0-0.d" + c_type + ".tw" + w_type + "DistanceMatrix.dat"
    time1 = data_path + "test" + c_num + "-0-0-0-0.d" + c_type + ".tw" + w_type + "TimeMatrix.dat"
    specs = data_path + "test" + c_num + "-0-0-0-0.d" + c_type + ".tw" + w_type + "Specs_sdp.dat"

    cmd = ["python", algor_source, distance, time1, specs, result_name, s_time, c_num, i_time]
    print(cmd)

    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    # 注意一定要修改MYSQL的wait_timeout，以增加程序运行时间
    if result.returncode == 0:
        # 进程正常结束
        sql = f"update process_table set status=1 where id={process_id}"
        CS.execute(sql)
        mysql.connection.commit()
        print("已完成")
    else:
        # 进程异常结束
        sql = f"update process_table set status=2 where id={process_id}"
        CS.execute(sql)
        mysql.connection.commit()
        print("运行失败")

    return '文件上传成功', 200


@app.route('/get-refer', methods=['GET'])
def get_refer():
    directory = '../GenerateRefer/refer/'
    items = os.listdir(directory)
    txt_files = [item for item in items if item.endswith('.txt')]
    files_length = []
    for txt_file in txt_files:
        with open(directory + txt_file, 'r') as file:
            length = 0
            for _ in file:
                length += 1
            files_length.append(length)

    file_names_without_extension = [file_name.rstrip(".txt") for file_name in txt_files]
    response = {
        'txt_files': file_names_without_extension,
        'files_length': files_length
    }

    return jsonify(response)


@app.route('/get-solution', methods=['GET'])
def get_solution():
    directory = '../GenerateRefer/refer/'
    data_name = request.args.get('name')
    txt_name = directory + data_name + '.txt'

    # 读取.txt文件内容
    txt_content = []
    with open(txt_name, 'r') as file:
        for line in file:
            # 将每行分割成浮点数列表
            row = [float(val) for val in line.split()]
            txt_content.append(row)

    length = len(txt_content)
    # 读取对应文件夹内容
    folder_name = directory + data_name + '_route'
    folder_content = []
    for i in range(length):
        index = i + 1
        route_file_name = folder_name + '/' + f"route{index}.txt"
        file_data = []
        with open(route_file_name, 'r') as file:
            for line in file:
                # 将每行分割成浮点数列表
                row = [float(val) for val in line.split()]
                file_data.append(row)
        folder_content.append(file_data)

    response = {
        'txt_content': txt_content,
        'folder_content': folder_content
    }

    return jsonify(response)


@app.route('/compare-solution', methods=['POST'])
def compare_solution():
    data = request.get_json()
    # 检查 data 是否成功获取

    solutions = data.get('solution')  # 获取解决方案列表
    solution1 = solutions[0]
    solution2 = solutions[1]

    # 读取参考解集
    file_name = solution1.get('file_name')
    refer_file_path = f"../GenerateRefer/refer/{file_name}.txt"
    refer_solution_set = []
    refer_avg_set = [0, 0, 0, 0, 0]
    with open(refer_file_path, 'r') as file:
        for line in file:
            # 将每行分割成浮点数列表
            solution = [float(val) for val in line.split()]
            refer_avg_set = [a + b for a, b in zip(refer_avg_set, solution)]
            refer_solution_set.append(solution)

    epsilon = 1
    for i in range(5):
        refer_avg_set[i] = refer_avg_set[i] / len(refer_solution_set) + epsilon

    # 参考解集
    reference_set = np.array(refer_solution_set)

    process_id1 = solution1.get('process_id')
    process_id2 = solution2.get('process_id')

    algor_name1 = solution1.get('algor_name')[0]
    algor_name2 = solution2.get('algor_name')[0]


    CS = mysql.connection.cursor()
    sql1 = f"select result_name from process_table where id={process_id1}"
    CS.execute(sql1)
    mysql.connection.commit()
    data = CS.fetchall()
    result_name1 = '../Result/' + data[0][0]

    sql2 = f"select result_name from process_table where id={process_id2}"
    CS.execute(sql2)
    mysql.connection.commit()
    data = CS.fetchall()
    result_name2 = '../Result/' + data[0][0]

    files_content1 = {}
    # 获取当前目录下的所有文件和文件夹名
    for filename in os.listdir(result_name1):
        # 检查文件扩展名是否为.txt
        if filename.endswith('final.txt'):
            # 打开并读取文件内容
            solution_set = []
            with open(result_name1 + '/' + filename, 'r') as file:
                for line in file:
                    # 将每行分割成浮点数列表
                    solution = [float(val) for val in line.split()]
                    solution_set.append(solution)
                # 将文件内容保存到字典中
                files_content1[filename] = solution_set

    files_content2 = {}
    # 获取当前目录下的所有文件和文件夹名
    for filename in os.listdir(result_name2):
        # 检查文件扩展名是否为.txt
        if filename.endswith('final.txt'):
            solution_set = []
            with open(result_name2 + '/' + filename, 'r') as file:
                for line in file:
                    # 将每行分割成浮点数列表
                    solution = [float(val) for val in line.split()]
                    solution_set.append(solution)
                # 将文件内容保存到字典中
                files_content2[filename] = solution_set

    algorithms_results = {
        algor_name2: files_content2,
        algor_name1: files_content1,
    }

    length = len(algorithms_results)

    igd_results = calculate_igd_for_algorithms(algorithms_results, reference_set)
    hv_results = calculate_hv_for_algorithms(algorithms_results)
    c_metric_results = calculate_c_metric_for_algorithms(algorithms_results)

    return jsonify(igd_results, hv_results, c_metric_results)


# 计算IGD
def calculate_igd_for_algorithms(algorithms_results, reference_set):
    igd_results = {}
    for algorithm_name, results in algorithms_results.items():
        igd_results[algorithm_name] = {}
        for result_key, solution_set in results.items():
            # 将解集转换为 numpy 数组
            solution_set_np = np.array(solution_set)
            # 计算 IGD
            igd_value = ea.indicator.IGD(solution_set_np, reference_set)
            # 保存 IGD 结果
            igd_results[algorithm_name][result_key] = igd_value

    return igd_results


# 计算HV
def calculate_hv_for_algorithms(algorithms_results):
    hv_results = {}
    for algorithm_name, results in algorithms_results.items():
        hv_results[algorithm_name] = {}
        for result_key, solution_set in results.items():
            # 将解集转换为 numpy 数组
            solution_set_np = np.array(solution_set)

            RefPoint = np.max(solution_set_np, axis=0) + 1
            RefPoint = np.array([RefPoint])

            # 计算 HV
            igd_value = ea.indicator.HV(solution_set_np, RefPoint)
            # 保存 HV 结果
            hv_results[algorithm_name][result_key] = igd_value

    return hv_results


# 计算C-metric
def dominates(row, candidateRow):
    """检查是否row支配candidateRow."""
    return all(r <= c for r, c in zip(row, candidateRow)) and any(r < c for r, c in zip(row, candidateRow))


def c_metric(A, B):
    """计算解集A覆盖解集B的程度C(A, B)."""
    num_dominated = 0
    for b in B:
        if any(dominates(a, b) for a in A):
            num_dominated += 1
    return num_dominated / len(B)


def calculate_c_metric_for_algorithms(algorithms_results):
    c_metric_results = {}
    algorithm_names = list(algorithms_results.keys())
    for name in algorithm_names:
        c_metric_results[name] = {}

    algor_name1, algor_name2 = algorithm_names

    # 对每一轮的解集进行比较
    for round_key in algorithms_results[algor_name1].keys():
        # 转换为 numpy 数组
        solution_set1_np = np.array(algorithms_results[algor_name1][round_key])
        solution_set2_np = np.array(algorithms_results[algor_name2][round_key])

        # 计算覆盖率
        c_value1 = c_metric(solution_set1_np, solution_set2_np)
        c_value2 = c_metric(solution_set2_np, solution_set1_np)

        # 保存结果
        c_metric_results[algor_name1][round_key] = c_value1
        c_metric_results[algor_name2][round_key] = c_value2

    return c_metric_results


if __name__ == '__main__':
    app.run(debug=True)
